/*************************************************************************
 *************************************************************************
 	 	 	 	 	 	 	M2SMA : PriorityScheduler.cpp
 *************************************************************************
 *
 	 Copyright (C) 2011
 	 M2SMA enhanced core, Steven Costiou, France
 *
 **************************************************************************
 **************************************************************************
 *
	FILE COMMENT ///TODO
 *
 **************************************************************************
 **************************************************************************
 *
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/
 *
 **************************************************************************
 **************************************************************************/

#include "PriorityScheduler.h"

PriorityScheduler::PriorityScheduler()
{
	initializeAttributes();
}

PriorityScheduler::~PriorityScheduler()
{
	eraseAllAgents();

	absolutePriorityVector->clear();
	veryHighPriorityVector->clear();
	mediumPriorityVector->clear();
	lowPriorityVector->clear();

	delete absolutePriorityVector;
	delete veryHighPriorityVector;
	delete mediumPriorityVector;
	delete lowPriorityVector;
}

void PriorityScheduler::initializeAttributes()
{
	this->setMode(PRIORITY_SCHEDULING);
	absolutePriorityVector = new map<string, Agent*>();
	veryHighPriorityVector = new map<string, Agent*>();
	mediumPriorityVector = new map<string, Agent*>();
	lowPriorityVector = new map<string, Agent*>();
}

void PriorityScheduler::addAgentWithPriority(Agent* anAgent, short int aPriority)
{
	newAgent(anAgent);

	switch(aPriority)
	{
		case ABSOLUTE_PRIORITY:
			this->absolutePriorityVector->insert(pair<string, Agent*> (anAgent->getName(), anAgent));
			break;

		case VERY_HIGH_PRIORITY:
			this->veryHighPriorityVector->insert(pair<string, Agent*> (anAgent->getName(), anAgent));
			break;

		case MEDIUM_PRIORITY:
			this->mediumPriorityVector->insert(pair<string, Agent*> (anAgent->getName(), anAgent));
			break;

		case LOW_PRIORITY:
			this->lowPriorityVector->insert(pair<string, Agent*> (anAgent->getName(), anAgent));
			break;

		default:
			throw new UnknownSchedulingPriorityException(aPriority);
			break;
	}
}

void PriorityScheduler::removeAndClearAgent(Agent* anAgent)
{
	if(lowPriorityVector->find(anAgent->getName()) != lowPriorityVector->end())
	{
		lowPriorityVector->erase(anAgent->getName());
		this->decreaseAgentCounter();
		return;
	}

	if(mediumPriorityVector->find(anAgent->getName()) != mediumPriorityVector->end())
	{
		mediumPriorityVector->erase(anAgent->getName());
		this->decreaseAgentCounter();
		return;
	}

	if(veryHighPriorityVector->find(anAgent->getName()) != veryHighPriorityVector->end())
	{
		veryHighPriorityVector->erase(anAgent->getName());
		this->decreaseAgentCounter();
		return;
	}

	if(absolutePriorityVector->find(anAgent->getName()) != absolutePriorityVector->end())
	{
		absolutePriorityVector->erase(anAgent->getName());
		this->decreaseAgentCounter();
		return;
	}

	throw new UnknownAgentDeletionException((anAgent->getName()).c_str());
}

void PriorityScheduler::cycle()
{
	if(this->getMode() != PRIORITY_SCHEDULING)
		throw new ForbiddenSchedulingModeException(this->getMode());

	performPriorityScheduling();
}

void PriorityScheduler::performPriorityScheduling()
{
	map<string, Agent *>::iterator it;

	for(it = absolutePriorityVector->begin(); it != absolutePriorityVector->end(); it++)
		(*it).second->live();

	for(it = veryHighPriorityVector->begin(); it != veryHighPriorityVector->end(); it++)
		(*it).second->live();

	for(it = mediumPriorityVector->begin(); it != mediumPriorityVector->end(); it++)
		(*it).second->live();

	for(it = lowPriorityVector->begin(); it != lowPriorityVector->end(); it++)
		(*it).second->live();
}
